package com.robert.demo.common.utils;

import com.robert.common.commonutil.bean.vo.ResultData;
import com.robert.common.commonutil.util.UUIDUtils;
import com.robert.demo.entity.OptLogInfo;
import com.robert.demo.service.IOptLogService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * PostLogHandler: 记录第三方接口日志
 *
 * @author zhaoshengtao
 * @date 2024/02/20
 */
@Slf4j
@Component
public class PostLogHandler {

    private static final ConcurrentHashMap<String, OptLogInfo> LOG_MAP = new ConcurrentHashMap<>();

    private static final ThreadLocal<String> REQUEST_ID = new ThreadLocal<>();

    @Autowired
    private IOptLogService optLogService;
    private static PostLogHandler postLogHandler;

    public static void main(String[] args) {
        String start = PostLogHandler.start("测试接口", "http://localhost:8001/log","{name: '张三'}", 1,
                "这是一个测试");
        try {
            // 模拟接口调用
            ResultData success = ResultData.success(start);
            PostLogHandler.end(success.toString());
        }catch (Exception e){
            PostLogHandler.exception(e, "请求失败");
        }
    }


    @PostConstruct
    public void init() {
        postLogHandler = this;
        postLogHandler.optLogService = this.optLogService;
    }

    public static String start(String name,  String url, String request, Integer userId){
        return start(name, url, request, userId, null);
    }
    /**
     * 开始
     * @param name 接口名
     * @param url 接口url
     * @param request  请求参数
     * @param userId  请求用户
     * @param memo  备注说嘛
     * @return uuid全局唯一
     */
    public static String start(String name,  String url, String request, Integer userId, String memo){
        // requestId
        String traceId = UUIDUtils.getUUID();
        // 生成对象
        OptLogInfo optLogInfo = OptLogInfo.builder().name(name).reqUrl(url).state("0").reqParams(request).memo(memo)
                .createTime(new Date()).updateTime(new Date()).userId(userId)
                .version("1.0").takeTime(System.currentTimeMillis()).requestId(traceId).build();
        REQUEST_ID.set(traceId);
        LOG_MAP.put(traceId, optLogInfo);
        return traceId;
    }



    /**
     *  接口调用结束，关闭
     * @param response 响应结果
     */
    public static void end(String response){
        end(response, null);
    }
    /**
     *  接口调用结束，关闭
     * @param response 响应结果
     * @param memo 备注说明， 直接覆盖
     */
    public static void end(String response, String memo){
        OptLogInfo optLog = getOptLog();
        if(optLog == null){
            return;
        }
        optLog.setResult(response);
        optLog.setState("1");
        optLog.setMemo(memo);
        insertLog(optLog);
        REQUEST_ID.remove();
    }

    /**
     * 追加日志说明
     * @param memo  在之前的基础上追加
     */
    public static void addMemo(String memo){
        OptLogInfo optLog = getOptLog();
        if(optLog == null){
            return;
        }
        optLog.setMemo(optLog.getMemo() == null ? StringUtils.EMPTY : optLog.getMemo() + ";" +memo);
    }

    /**
     * 异常处理
     * @param e 异常信息
     * @param memo  备注说明  null 则不设置
     */
    public static void exception(Exception e, String memo){
        OptLogInfo optLog = getOptLog();
        if(optLog == null){
            return;
        }
        optLog.setState("2");
        String result = ExceptionUtil.stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace());//记录异常信息
        optLog.setResult(result);
        if(memo != null) {
            optLog.setMemo(memo);
        }
        insertLog(optLog);
        REQUEST_ID.remove();
    }

    /**
     *  根据start方法返回的traceId，获取日志对象，可以自定义设置对象
     */
    public static OptLogInfo getOptInfo(String requestId){
        return LOG_MAP.get(requestId);
    }
    /**
     *  无参获取日志对象，可以自定义设置对象
     */
    public static OptLogInfo getOptInfo(){
        return getOptLog();
    }

    /**
     * 存储日志对象
     */
    public static void save(OptLogInfo optLogInfo){
        insertLog(optLogInfo);
    }


    private static OptLogInfo getOptLog(){
        String traceId = REQUEST_ID.get();
        if(traceId== null){
            log.error("未获取到requestId");
            return null;
        }
        log.info("获取到的ID={}", traceId);
        OptLogInfo optLogInfo = LOG_MAP.get(traceId);
        if(optLogInfo == null){
            log.error("未获取到日志对象, requestId={}",REQUEST_ID);
            return null;
        }
        optLogInfo.setTakeTime(System.currentTimeMillis() - optLogInfo.getTakeTime());
        LOG_MAP.remove(traceId);
        return optLogInfo;
    }

    /**
     * 异步存储
     */
    private static void insertLog(OptLogInfo optLogInfo){
        //启动一个线程，执行报错日志，防止影响主请求
        // 优化，改用线程池或者队列
        new Thread(() -> {
            try {
                postLogHandler.optLogService.insertInfo(optLogInfo);
            } catch (Exception e) {
                log.error(e.getMessage(),e);
            }
        }).start();
    }

}
